import json
import math
import random
import time
import functools
import datetime
import requests

from flask import Blueprint, jsonify, request, make_response, redirect
from application.models.users.user import db, User, SfLogin, VipRecord, Vip, Tags, Ctype, CourseType, Course, Tcourse, Orders
from application.captcha.captcha import captcha
from RedisTool import r
from tools.comm import sendMsg, get_ali_object
from tools.myjwt import mjwt
from qiniu import Auth
user_blue = Blueprint("user_blue", __name__)


# 权限认证
def islogin(func):
    @functools.wraps(func)
    def wrapper():
        return func()

    return wrapper


# 获取图片验证码
@user_blue.route("/getcode")
@islogin
def getcode():
    # 生成图片验证码 text文字， image图片流
    name,text,image = captcha.generate_captcha()
    # 从页面获取uuid作为redis key
    uuid = str(request.args.get("uuid"))
    # 存入redis
    r.str_add(uuid,str(text),60)
    # 以流方式返回图片验证码
    res = make_response(image)
    res.headers["Content-Type"] = "image/png"
    return res


# 发送短信验证码
@user_blue.route("/sendSmsCode", methods=["POST"])
@islogin
def sendSmsCode():
    data = request.data
    if data:
        data = json.loads(data)
        # 获取三个参数
        uuid = data.get("uuid")
        mobile = data.get("mobile")
        procode = data.get("procode")
        # 通过uuid查询redis
        value = r.str_get(uuid)
        # 两个验证码对比，如果成功调用短信平台发送短信 # lower() 转换为小写
        if value:
            if procode.lower() == value.lower():
                # 验证一分钟只能发送一次
                mcode = r.str_get(mobile)
                if mcode:
                    return jsonify({"code": 403, "msg": "一分钟只能发送一次"})
                    # 生成5位随机数
                scode = "%06d" % random.randint(0, 999999)
                # scode = random.randint(10000, 99999)
                scode = str(scode)
                flag = sendMsg(mobile, scode)
                if flag == True:
                    r.str_add(mobile, scode, 60)
                    r.str_del(uuid)
                    return jsonify({"code": 200, "msg": "发送成功"})
                else:
                    return jsonify({"code": 404, "msg": "发送失败"})
            else:
                return jsonify({"code": 402, "msg": "图形验证码错误"})
        else:
            return jsonify({"code": 401, "msg": "图形验证码不存在"})


# 注册登录接口
@user_blue.route("/login", methods=["POST"])
@islogin
def login():
    # 获取参数、手机号、验证码
    data = request.data
    if data:
        data = json.loads(data)
        uuid = data.get("uuid")
        procode = data.get("smscode")
        mobile = data.get("mobile")
        # 根据手机号跟redis获取验证码
        mobile_code = r.str_get(mobile)
        # 验证码是否相同
        if str(mobile_code) == str(procode):
            # 如果相同查询数据库user表
            user = User.query.filter(User.mobile == mobile).first()
            # 删除redis中的验证码
            if user:
                r.str_del(mobile)
            else:
                # 如果不存在写入用户表
                u = User(mobile=mobile, nikename=mobile)
                db.session.add(u)
                db.session.commit()
                # 如果存在返回用户信息
                user = User.query.filter(User.mobile == mobile).first()
            # 用用户信息生成jwt.token
            token = mjwt.jwt_encode(data={"data": {'uid': user.id, 'exp': int(time.time())}})
            return jsonify({"code": 200, "msg": "登录成功", "token": token, "userid": user.id})
        # 如果不相同返回错误
        else:
            return jsonify({"code": 400, "msg": "验证码错误"})
    else:
        return jsonify({"code": 401, "msg": "数据不存在"})


# 获取weibo地址
@user_blue.route('/getwxurl')
def getwburl():
    client_id = '3674019597'
    redirect_uri = "http://127.0.0.1:8000/user/weiboCallback/"
    url = "https://api.weibo.com/oauth2/authorize?client_id=%s&response_type=code&redirect_uri=%s" % (client_id, redirect_uri)
    return jsonify({'code': 200, 'url': url})


# weibo回调接口
@user_blue.route('/weiboCallback/')
def weiboCallback():

    # 获取code
    code = request.args.get('code')
    # 向access-token接口发起post请求
    data = {"client_id": '3674019597', "client_secret": "7ae99bc0d54ead29fc8d1b9fabd78587",
            "grant_type": "authorization_code",
            'redirect_uri': "http://127.0.0.1:8000/user/weiboCallback/", 'code': code}
    res = requests.post('https://api.weibo.com/oauth2/access_token', data=data)
    # 解析参数,token,uid
    mes = json.loads(res.text)
    token = mes['access_token']
    uid = mes['uid']

    # 查询三方登录中uid是否存在，如果存在，查询用户表，用用户信息生成token跳转到vue页面
    # sf = SfLogin.query.filter(SfLogin.uid == uid).first()
    # if sf:
    #     user = User.query.filter(User.id == sf.userid).first()
    #     data={'data':{"userid":user[0],"exp":int(time.time())}}
    #     token = mjwt.jwt_encode(data)
    #     return redirect('http://localhost:8080/#/upateToken?userid='+str(user[0])+"&token="+token)

    sql = "select user.id from user inner join sf_login on user.id=sf_login.userid where sf_login.uid='%s'" % (uid)
    user = db.session.execute(sql)
    # orm查询
    # 判断是否查询到
    if user:
        for i in user:
            data = {'data': {"userid": i[0], "exp": int(time.time())}}
            token = mjwt.jwt_encode(data)
            return redirect('http://localhost:8080/#/upateToken?userid=' + str(i[0]) + "&token=" + token)
    # 不存在跳转到vue绑定页面，token uid传递过去
    return redirect('http://localhost:8080/#/bindMobile?uid=' + uid + "&token=" + token)


# 绑定手机号
@user_blue.route("/bindMobile", methods=["POST"])
def bindMobile():
    data = json.loads(request.data)
    mobile = data["mobile"]
    uid = data["uid"]
    token = data["token"]
    # 先查询用户表，如果用户手机号存在
    user = User.query.filter(User.mobile == mobile).first()
    if not user:
        # 添加用户
        u = User(mobile=mobile, nikename=mobile)
        db.session.add(u)
        db.session.commit()
        # 获取用户信息
        user = User.query.filter(User.mobile == mobile).first()

    sfuser = SfLogin(userid=user.id, webfrom="wb", uid=uid, token=token)
    db.session.add(sfuser)
    db.session.commit()
    # 如果不存在，写入user表
    # 获取userid, 写入第三方登录表， 生成token返回
    data = {"data": user.id, "exp": int(time.time())}
    token = mjwt.jwt_encode(data)
    # return redirect("http://localhost:8080/#/bindMobile?uid="+str(uid)+"&token="+token)
    return jsonify({'userid': str(user.id), 'token': token})


# 购买vip生成订单
@user_blue.route("/buy", methods=["POST"])
def buy():
    # 获取参数
    data = json.loads(request.data)
    userid = data["userid"]
    year = data["year"]
    money = 200
    tmoney = money * int(year)
    order_no = str(int(time.time())) + str(userid) + str(random.randint(100,999))
    # 写入vip记录表
    viprecord = VipRecord(order_no=order_no, userid=userid, year=year, money=tmoney, active_money=tmoney, status=1)
    db.session.add(viprecord)
    db.session.commit()
    # 支付，返回支付url
    pay = get_ali_object()
    # 生成支付的url
    query_params = pay.direct_pay(
        subject="test",  # 商品简单描述
        out_trade_no=str(order_no),  # 用户购买的商品订单号（每次不一样） 20180301073422891
        total_amount=float(100.00),  # 交易金额(单位: 元 保留俩位小数)
    )
    pay_url = "https://openapi.alipaydev.com/gateway.do?{0}".format(query_params)  # 支付宝网关地址（沙箱应用）
    return jsonify({"code": 200, "url": pay_url})


# vip 添加订单流水号
# @user_blue.route("/callback")
# def callback():
#     # 接收参数
#     data = request.args
#     datames = {k:v for k,v in data.items()}
#     # 删除字典中的key为sign的记录
#     sign = datames.pop("sign")
#     # 鉴权 订单号 流水号
#     pay = get_ali_object()
#     flag = pay.verify(datames, sign)
#
#     if flag == True:
#         # 支付宝流水号
#         transaction_no = datames["trade_no"]
#         print("支付宝流水号----transaction_no>>>>>>>>",transaction_no)
#         # 订单号
#         order_no = datames["out_trade_no"]
#         print("订单号-----order_no>>>>>>>",order_no)
#         # 事务处理
#         # try:
#         # 订单号更新订单表
#         record = VipRecord.query.filter(VipRecord.order_no == order_no).first()
#         record.status = 2
#         record.transaction_no = transaction_no
#         db.session.add(record)
#         # 更新用户表
#         User.query.filter(User.id == record.userid).update({"level":2})
#         # 更新vip表
#         vip = Vip.query.filter(Vip.userid == record.userid, Vip.status == 1).first()
#         if vip is not None:
#             # 结束时间+购买年限
#             etime = vip.e_time.split("-")
#             tyear = int(etime[0]) + int(record.year)
#             yearstr = "-"
#             etime[0] = str(tyear)
#             retime = yearstr.join(etime)
#             vip.e_time = retime
#             db.session.add(vip)
#         else:
#             year = 365 * int(record.year)
#             retime = datetime.datetime.now()+datetime.timedelta(days=year)
#             # nowyear = datetime.date.strftime(datetime.datetime.now(),"%Y-%m-%d %H:%m:%s")
#             # etime = nowyear.split("-")
#             # tyear = int(etime[0])+int(record.year)
#             # etime[0] = str(tyear)
#             # yearstr = "-"
#             # retime = yearstr.join(etime)
#             vip = Vip(userid=record.userid, s_time=datetime.datetime.now(), e_time=retime)
#             db.session.add(vip)
#         db.session.commit()
#         # except:
#         #     db.session.rollback()
#     else:
#         print("鉴权失败")
#     return "付款成功"


@user_blue.route("/callback")
def callback():
    # 接收参数
    data = request.args
    datames = {k:v for k,v in data.items()}
    # 删除字典中key为sign的记录
    sign = datames.pop('sign')
    print(sign)
    # 鉴权 订单号 流水号
    pay = get_ali_object()
    flag = pay.verify(datames,sign)
    print(flag)
    if flag == True:
        # 订单号
        order_no = datames['out_trade_no']
        # print('11111111',order_no)
        # 支付宝流水号
        transaction_no = datames['trade_no']
        # split订单号:
        orderlist = order_no.split(":")
        order_no = orderlist[0]
        type = int(orderlist[1])
        # 事务处理
        try:
            if type == 1:
                # 根据订单号 更新订单表
                record = VipRecord.query.filter(VipRecord.order_no == order_no).first()
                # sql = "select * from vip_record where order_no = '%s'"%(order_no)
                # print(sql)
                # res = db.session.execute(sql)
                # record = res.fetchone()
                record.status = 2
                record.transaction_no = transaction_no
                db.session.add(record)
                # 更新用户表
                User.query.filter(User.id == record.userid).update({"level":2})
                # 更新vip表
                vip = Vip.query.filter(Vip.userid == record.userid,Vip.status == 1).first()
                if vip is not None:
                    # 结束时间 + 购买年限
                    etime = vip.e_time.split("-")
                    tyear = int(etime[0]) + int(record.year)
                    yearstr = "-"
                    etime[0] = str(tyear)
                    retime = yearstr.join(etime)
                    vip.e_time = retime
                    db.session.add(vip)
                else:
                    # nowyear = datetime.date.strftime(datetime.datetime.now(),"%Y-%m-%d %H:%m:%s")
                    # etime = nowyear.split("-")
                    # tyear = int(etime[0]) + int(record.year)
                    # etime[0] = str(tyear)
                    # yearstr = "-"
                    # retime = yearstr.join(etime)

                    year = 365*int(record.year)
                    retime = datetime.datetime.now() + datetime.timedelta(days=year)
                    vip = Vip(userid=record.userid,s_time=datetime.datetime.now(),e_time=retime)
                    db.session.add(vip)
                db.session.commit()
            elif type == 2:
                # 课程订单更新状态，支付宝的流水号
                orders = Orders.query.filter(Orders.order_no == order_no).first()
                orders.status = 2
                orders.trans_no = transaction_no
                db.session.add(orders)
                # 更新订单表状态，根据订单详情表查询商品，去商品表中减少商品汇总库存
                for i in orders.details:
                    tcourse = Tcourse.query.filter(Tcourse.id == i.courseid).first()
                    tcourse.store = tcourse.store - i.number
                    db.session.add(tcourse)
                db.session.commit()
        except:
            db.session.rollback()
    else:
        print("鉴权失败")
    return "ok"


# 展示课程类别，课程分类，课程类别
@user_blue.route("/getTags", methods=["GET"])
def getTags():
    # 课程类别
    tags = Tags.query.all()
    tagelist = [{"id": i.id, "name": i.name} for i in tags]
    # 课程类别 ~~免费~~会员
    types = Ctype.query.all()
    typeslist = [{"id": i.id, "name": i.name} for i in types]
    # 课程分类
    ctype = CourseType.query.all()
    ctypelist = [{"id":i.id,
                  "name": i.name,
                  "url": i.url,
                  "number": i.number,
                  "times": i.times,
                  "tcomment": i.tcomment,
                  "descrip": i.descrip,
                  }for i in ctype
                 ]
    return jsonify({"code": 200, "tags":tagelist, "types":typeslist, "clist": ctypelist})


# 七牛云上传
@user_blue.route("/get_qiniu", methods=["GET"])
def get_qiniu():
    # 需要填写你的 Access Key 和 Secret Key
    access_key = '7wlTPiESQkRS70TVVkW2kXQJ5fb_ufQLrHSg-kwi'
    secret_key = 'bxsi4y0qT51LxsxbriBD75AeJTQyEeJZUfet0B8s'
    # 构建鉴权对象
    q = Auth(access_key, secret_key)
    # 要上传的空间
    bucket_name = 'h2205a-lpx'
    # 生成上传 Token，可以指定过期时间等
    token = q.upload_token(bucket_name)
    return jsonify({"code": 200, "token":token})


# 添加课程表
@user_blue.route("/addCourse", methods=["POST"])
def addCourse():
    # 获取参数
    data = json.loads(request.data)
    # 写入课程表
    course = Course(name=data["name"], url=data["url"], descrip=data["desc"], ctype=data["type"])
    db.session.add(course)
    # 获取新加的课程的id
    scourse = Course.query.filter(Course.name == data["name"]).first()
    # 写入课程表标签表
    for i in data["tags"]:
        sql = "insert into course_tag(courseid,tagid) values(%d,%d)" % (scourse.id, int(i))
        db.session.execute(sql)
        # 课程分类表
    for i in data["ctype"]:
        sql = "insert into course_cate(courseid,course_typeid) values(%d,%d)" % (scourse.id, int(i))
        db.session.execute(sql)
    db.session.commit()
    return "ok"


# 课程分页  原生SQL
@user_blue.route("/getCourse")
def getCourse():
    # 获取当前页面
    page = int(request.args.get("page"))
    page_size = 3
    # 获取条件
    # 获取上线、即将上线条件
    online = int(request.args.get("is_publish"))
    # 获取类别
    types = int(request.args.get("types"))
    # 获取类别
    tags = int(request.args.get("tags"))
    # 获取排序字段
    orderpara = request.args.get("orderpara")
    # 重构where条件
    where = "1=1"
    if online:
        where = where + " and c.is_publish=" + str(online)
    if types > 0:
        where = where + " and c.ctype=" + str(types)
    # 排序
    orderby = " order by c.views desc"
    if orderpara == "new":
        orderby = " order by c.create_time desc"
    start = math.ceil((page-1)*page_size)
    # 查询一共有多少条记录
    if tags > 0:
        countsql = "select count(c.id) as tcount from course as c inner join course_tag as ct on c.id=ct.courseid where ct.tagid=" + str(tags)+' and '+where
    else:
        countsql = "select count(c.id) as tcount from course as c where"+where
    # print("111sql=",countsql)
    cres = db.session.execute(countsql)
    cdata = cres.fetchone()
    total = cdata["tcount"]
    # print(total)
    # 查询当前页记录
    if tags > 0:
        sql = "select c.* from course as c inner join course_tag as ct on c.id=ct.courseid where ct.tagid=" + str(tags) + ' and ' + where + orderby + " limit " + str(start) + ',' + str(page_size)
    else:
        sql = "select c.* from course as c where " + where+orderby+" limit "+str(start)+","+str(page_size)
    # print("222sql=",sql)
    res = db.session.execute(sql)
    data = res.fetchall()
    clist = [{"id": i.id, "name": i.name, "url": i.url, "views": i.views}for i in data]
    return jsonify({"code": 200, "clist": clist, "total": total, "page_size": page_size,"tags":tags})


# # 课程分页 ORM
# @user_blue.route("/getCourse")
# def getCourse():
#     # 获取参数page
#     page = int(request.args.get("page"))
#     # 获取上线，即将上线条件
#     online = int(request.args.get("is_publish"))
#     # 查询总条数
#     total = Course.query.filter(Course.is_publish == online).count()
#     # 定义每页显示多少条
#     page_size = 3
#     # 查询当前页记录
#     start = math.ceil((page-1) * page_size)
#     # 获取排序字段
#     orderpara = request.args.get("orderpara")
#     if orderpara == "new":
#         course = Course.query.order_by(Course.create_time.desc()).filter(Course.is_publish == online).offset(start).limit(page_size).all()
#     else:
#         course = Course.query.order_by(Course.views.desc()).filter(Course.is_publish == online).offset(start).limit(page_size).all()
#     courseList = [{"id": i.id, "name": i.name, "url": i.url, "views": i.views}for i in course]
#     # 返回结果
#     return jsonify({"code": 200, "clist": courseList, "total": total, "page_size": page_size})






















































